package com.u3k.app.mid.utils.net;

import com.u3k.mid.LogUtils;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class HttpClient {
    static String TAG = HttpClient.class.getSimpleName();
    private static ExecutorService executorService;
    private static final Deque<HttpTask> readyAsyncCalls = new ArrayDeque();
    private static final Deque<HttpTask> runningAsyncCalls = new ArrayDeque();
    private int connectTimeout = 10000;
    private int maxRequests = 64;
    private int maxRequestsPerHost = 5;
    private int readTimeout = 10000;

    class ClientThreadFactory implements ThreadFactory {
        private AtomicInteger count;

        private ClientThreadFactory() {
            this.count = new AtomicInteger(0);
        }

        public Thread newThread(Runnable runnable) {
            Thread thread = new Thread(runnable);
            String str = "u3k_httpclient" + this.count.addAndGet(1);
            System.out.println(str);
            thread.setName(str);
            return thread;
        }
    }

    private void promoteCalls() {
        if (runningAsyncCalls.size() < this.maxRequests && !readyAsyncCalls.isEmpty()) {
            Iterator it = readyAsyncCalls.iterator();
            while (it.hasNext()) {
                HttpTask httpTask = (HttpTask) it.next();
                if (runningCallsForHost(httpTask) < this.maxRequestsPerHost) {
                    it.remove();
                    runningAsyncCalls.add(httpTask);
                    executorService().execute(httpTask);
                }
                if (runningAsyncCalls.size() >= this.maxRequests) {
                    return;
                }
            }
        }
    }

    private int runningCallsForHost(HttpTask httpTask) {
        int i = 0;
        for (HttpTask host : runningAsyncCalls) {
            i = host.host().equals(httpTask.host()) ? i + 1 : i;
        }
        return i;
    }

    public void callFinished(HttpTask httpTask) {
        synchronized (this) {
            if (runningAsyncCalls.remove(httpTask)) {
                promoteCalls();
            } else {
                throw new AssertionError("Call wasn't in-flight!");
            }
        }
    }

    public void download(Request request, String str, DownloadCallback downloadCallback) {
        LogUtils.LogError(TAG, "download  url=" + request.url);
        Runnable httpDownloader = new HttpDownloader(this, request, str, downloadCallback);
        if (runningAsyncCalls.size() >= this.maxRequests || runningCallsForHost(httpDownloader) >= this.maxRequestsPerHost) {
            readyAsyncCalls.add(httpDownloader);
            return;
        }
        runningAsyncCalls.add(httpDownloader);
        executorService().execute(httpDownloader);
    }

    public ExecutorService executorService() {
        ExecutorService executorService;
        synchronized (this) {
            if (executorService == null) {
                executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue(), new ClientThreadFactory());
            }
            executorService = executorService;
        }
        return executorService;
    }

    public int getConnectTimeout() {
        return this.connectTimeout;
    }

    public int getReadTimeout() {
        return this.readTimeout;
    }

    public Response request(Request request) {
        return new HttpCall(this, request, null).processRequest();
    }

    public void request(Request request, Callback callback) {
        LogUtils.LogError(TAG, "request  url=" + request.url);
        Runnable httpCall = new HttpCall(this, request, callback);
        if (runningAsyncCalls.size() >= this.maxRequests || runningCallsForHost(httpCall) >= this.maxRequestsPerHost) {
            readyAsyncCalls.add(httpCall);
            return;
        }
        runningAsyncCalls.add(httpCall);
        executorService().execute(httpCall);
    }
}
